﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using ServBus.ListForm2010.Utility;
using ServBus.ListForm2010.Resources;
using System.Collections;
using System.Xml;
using ServBus.ListForm2010.Common.WFXSNOperator;
using ServBus.ListForm2010.License;
using Microsoft.SharePoint.Workflow;
using System.Diagnostics;


namespace ServBus.ListForm2010.Layouts.ListForm2010
{
    public partial class ListFormWFManagement : LayoutsPageBase
    {

        private string _contentTypeName;
        private License.License _license;
        private string _errorMsg = "";
        private static readonly DllResource Resource = new DllResource("ServBus.ListForm2010.Common.Resources|AppPages");

        private void errorLog(Exception ex, bool internalError)
        {

            if (internalError)
            {
                errorPanel.Visible = true;
            }
            else
            {
#if DEBUG
                errorPanel.Visible = false;
                LTException.Text = ex.Message;
                LTException.Visible = true;
#else
                LTException.Text = ex.Message;
                LTException.Visible = false;
#endif
            }
            ErrorLog.Write("ListFormWFManagement" + "\r\n" + Request.Url + "\r\n" + ex.Message + "\r\n" + ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
        }

        #region Page

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (!Page.IsPostBack)
                {
                    mainPanel.Visible = false;
                    titleLabel.Text = Resource.GetString("PageTitle_WorkflowForms");
                    Activations activations = new Activations(SPContext.Current.Site.WebApplication);
                    if (!activations.IsActivationValid(SPContext.Current.Web, out _errorMsg))
                    {
                        errorLog(new Exception(_errorMsg), false);
                    }
                    else
                    {
                        _license = LicenseContainer.ProductLicense;
                        if (_license.FeatureSet == FeatureSet.Professional)
                        {
                            InitialData();
                        }
                        else
                        {
                            errorLog(new Exception(Resource.GetString("Error_FeatureNotSupport")), false);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }

        private void InitialData()
        {
            tlLabel.Visible = false;
            wfDdlLabel.Visible = false;
            wfDdl.Visible = false;
            ctDdlLabel.Visible = false;
            ctDdl.Visible = false;
            okButton.Visible = false;
            cancelButton.Visible = false;
            if (!string.IsNullOrEmpty(Request["source"]))
            {
                Activations activations = new Activations(SPContext.Current.Site.WebApplication);
                if (!activations.IsActivationValid(SPContext.Current.Web, out _errorMsg))
                {

                    errorLog(new Exception(_errorMsg), false);
                }
                else
                {

                    wfDdl.Items.Clear();
                    ctDdl.Items.Clear();

                    Guid siteId = SPContext.Current.Site.ID;
                    Guid webId = SPContext.Current.Web.ID;

                    Guid listId = new Guid(Request["source"]);

                    SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (SPSite site = new SPSite(siteId))
                        {
                            using (SPWeb web = site.OpenWeb(webId))
                            {
                                SPList list = web.Lists[listId];
                                Dictionary<Guid, SPWorkflowAssociation> wfAss = new Dictionary<Guid, SPWorkflowAssociation>();
                                SPWorkflowAssociationCollection wfs = list.WorkflowAssociations;
                                if (wfs.Count > 0)
                                {
                                    WfRemoveDuplicates(wfs, ref wfAss);
                                }

                                foreach (SPContentType ct in list.ContentTypes)
                                {
                                    SPWorkflowAssociationCollection wfs_ct = ct.WorkflowAssociations;
                                    WfRemoveDuplicates(wfs_ct, ref wfAss);
                                }

                                if (wfAss.Keys.Count > 0)
                                {
                                    wfDdlLabel.Text = Resource.GetString("ListBus_Settings_wfSelect");
                                    wfDdlLabel.Visible = true;
                                    ctDdlLabel.Text = Resource.GetString("ListBus_Settings_ctSelect");
                                    ctDdlLabel.Visible = true;
                                    okButton.Text = Resource.GetString("ListBus_Settings_BtnOK");
                                    okButton.Enabled = false;
                                    okButton.Visible = true;
                                    cancelButton.Visible = true;
                                    cancelButton.Text = Resource.GetString("ListBus_Settings_BtnCancel");
                                    displayFormLabel.Text = Resource.GetString("FormView_display");
                                    editFormLabel.Text = Resource.GetString("FormView_edit");

                                    foreach (Guid wfBaseId in wfAss.Keys)
                                    {

                                        SPWorkflowAssociation wf = wfAss[wfBaseId];
                                        ListItem item = new ListItem(wf.Name, Convert.ToString(wf.Id));
                                        wfDdl.Items.Add(item);
                                        if (wfDdl.Items.Count == 1) WfChanged(item);
                                    }
                                    mainPanel.Visible = true;
                                    ctDdl.Visible = true;
                                }
                                else
                                {
                                    errorLog(new Exception(Resource.GetString("Error_NoWfExist")), false);
                                }
                            }
                        }
                    });
                    wfDdl.Visible = true;
                }
            }
        }

        private void WfRemoveDuplicates(SPWorkflowAssociationCollection wfs, ref Dictionary<Guid, SPWorkflowAssociation> wfAss)
        {
            foreach (SPWorkflowAssociation wf in wfs)
            {
                if (wfAss.Keys.Contains(wf.BaseId))
                {
                    if (wf.Created.CompareTo(wfAss[wf.BaseId].Created) < 0)
                    {
                        continue;
                    }
                    else
                    {
                        wfAss[wf.BaseId] = wf;
                    }
                }
                else
                {
                    wfAss.Add(wf.BaseId, wf);
                }
            }
        }

        private void WfChanged(ListItem wfItem)
        {
            try
            {
                if (wfItem == null) return;
                okButton.Enabled = false;
                ctDdl.Items.Clear();
                tlLabel.Text = "";

                Guid siteId = SPContext.Current.Site.ID;
                Guid webId = SPContext.Current.Web.ID;
                Guid listId = new Guid(Request["source"]);

                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (SPSite site = new SPSite(siteId))
                    {
                        using (SPWeb web = site.OpenWeb(webId))
                        {
                            web.AllowUnsafeUpdates = true;
                            SPList list = web.Lists[listId];
                            SPWorkflowAssociation wf = null;
                            wf = list.WorkflowAssociations[new Guid(wfItem.Value)];
                            if (wf == null)
                            {
                                foreach (SPContentType ct in list.ContentTypes)
                                {
                                    wf = ct.WorkflowAssociations[new Guid(wfItem.Value)];
                                    if (wf != null) break;
                                }
                            }
                            if (wf != null)
                            {
                                tlLabel.Text = Convert.ToString(wf.TaskListId);
                                SPList taskList = web.Lists[wf.TaskListId];
                                SPContentType wfTaskCt = site.RootWeb.ContentTypes[wf.TaskListContentTypeId];
                                foreach (SPContentType taskCt in taskList.ContentTypes)
                                {
                                    if (taskCt.Id.IsChildOf(wf.TaskListContentTypeId))
                                    {
                                        ctDdl.Items.Add(taskCt.Name);
                                        if (ctDdl.Items.Count == 1) CtChanged(taskCt.Name);
                                    }
                                }
                            }
                            else
                            {
                                errorLog(new Exception(Resource.GetString("Error_WfDoesNotExist")), false);
                            }

                        }
                    }
                });
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }
        protected void WfDdlChanged(object sender, EventArgs e)
        {
            try
            {
                errorPanel.Visible = false;
                LTException.Visible = false;
                WfChanged(wfDdl.SelectedItem);
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }
        protected void CtDdlChanged(object sender, EventArgs e)
        {
            try
            {
                errorPanel.Visible = false;
                LTException.Visible = false;
                _contentTypeName = ctDdl.SelectedItem.Text;
                CtChanged(_contentTypeName);
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }

        protected void CreateFormRdChanged(object sender, EventArgs e)
        {
            okButton.Enabled = true;
        }

        protected void ModifyFormRdChanged(object sender, EventArgs e)
        {
            if (ModifyFormRd.Checked)
            {
                SpecificViewRd.Checked = false;
                dispViewDdl.Enabled = false;
                editViewDdl.Enabled = false;

                DefaultFormRd.Checked = false;
                deleteCB.Checked = false;
                deleteCB.Enabled = false;
            }
            okButton.Enabled = true;

        }

        protected void SpecificViewRdChanged(object sender, EventArgs e)
        {
            if (SpecificViewRd.Checked)
            {
                ModifyFormRd.Checked = false;
                DefaultFormRd.Checked = false;
                deleteCB.Checked = false;
                deleteCB.Enabled = false;

                dispViewDdl.Enabled = true;
                editViewDdl.Enabled = true;
            }
            okButton.Enabled = true;

        }

        protected void DefaultFormRdChanged(object sender, EventArgs e)
        {
            if (DefaultFormRd.Checked)
            {
                SpecificViewRd.Checked = false;
                dispViewDdl.Enabled = false;
                editViewDdl.Enabled = false;

                ModifyFormRd.Checked = false;
                deleteCB.Enabled = true;
            }
            okButton.Enabled = true;
        }

        protected void OkButtonClick(object sender, EventArgs e)
        {
            try
            {
                if (CreateFormRd.Visible)
                {
                    if (CreateFormRd.SelectedValue == "1")
                    {
                        CustomizeForm();
                    }
                }
                else
                {

                    if (ModifyFormRd.Checked)
                    {
                        ModifyExistingForm();
                    }
                    else if (SpecificViewRd.Checked)
                    {
                        UpdateViewConfigItem();
                    }
                    else if (DefaultFormRd.Checked)
                    {
                        DefaultForm();
                    }
                }
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }

        protected void CancelButtonClick(object sender, EventArgs e)
        {
            Response.Write("<script type='text/javascript'>window.frameElement.commitPopup('ok');</script>");
        }

        private void CtChanged(string ctName)
        {
            try
            {
                if (string.IsNullOrEmpty(ctName)) return;
                if (string.IsNullOrEmpty(tlLabel.Text)) return;
                okButton.Enabled = false;
                Guid siteId = SPContext.Current.Site.ID;
                Guid webId = SPContext.Current.Web.ID;
                Guid listId = new Guid(Request["source"]);

                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (SPSite site = new SPSite(siteId))
                    {
                        using (SPWeb web = site.OpenWeb(webId))
                        {
                            web.AllowUnsafeUpdates = true;
                            //if (_taskListId == Guid.Empty)
                            //{
                            //    SPList list = web.Lists[listId];
                            //    SPWorkflowAssociation wf = list.WorkflowAssociations[new Guid(wfDdl.SelectedItem.Value)];
                            //    _taskListId = wf.TaskListId; 
                            //}
                            SPList tasklist = web.Lists[new Guid(tlLabel.Text)];
                            SPContentType cType = tasklist.ContentTypes[ctName];
                            SPFile xsnFile = null;
                            if (!IsCustomizeFormExist(web, cType, ref xsnFile))
                            {
                                modifyPanel.Visible = false;

                                CreateFormRd.Items.Clear();
                                ListItem item1 = new ListItem(Resource.GetString("ListBus_Settings_Customize"), "1");

                                CreateFormRd.Items.Add(item1);
                                CreateFormRd.Visible = true;
                                //CustomizeFormRd.Text = Resource.GetString("ListBus_Settings_Customize");
                                //CustomizeFormRd.Visible = true;
                                //CreateLookupFormRd.Text = Resource.GetString("ListBus_Settings_LookupForm_Create");
                                //CreateLookupFormRd.Visible = true;
                            }
                            else
                            {
                                CreateFormRd.Visible = false;


                                ModifyFormRd.Text = Resource.GetString("ListBus_Settings_Modify");
                                ModifyFormRd.Checked = false;

                                SpecificViewRd.Text = Resource.GetString("ListBus_Settings_SpecificViews");
                                SpecificViewRd.Checked = false;
                                DefaultFormRd.Text = Resource.GetString("ListBus_Settings_Default");
                                DefaultFormRd.Checked = false;
                                deleteCB.Text = Resource.GetString("ListBus_Settings_Delete");
                                deleteCB.Checked = false;
                                deleteCB.Enabled = false;

                                dispViewDdl.Enabled = false;
                                editViewDdl.Enabled = false;

                                dispViewDdl.Items.Clear();
                                editViewDdl.Items.Clear();
                                string defalutView = "";
                                IEnumerable<string> views = getViews(xsnFile, ref defalutView);
                                Dictionary<string, string> configViews = GetViewConfigItem(web, tlLabel.Text, Convert.ToString(cType.Id));
                                bool configViewsExists = configViews.Count > 0;
                                foreach (string formView in views)
                                {
                                    //string formViewId = formView.Substring(0, formView.IndexOf('_'));
                                    string formViewName = formView.Substring(formView.IndexOf('_') + 1);
                                    ListItem listItem1 = new ListItem(formViewName, formViewName);
                                    ListItem listItem2 = new ListItem(formViewName, formViewName);
                                    ListItem listItem3 = new ListItem(formViewName, formViewName);
                                    dispViewDdl.Items.Add(listItem1);
                                    editViewDdl.Items.Add(listItem2);
                                }

                                if (configViewsExists)
                                {
                                    dispViewDdl.Items.FindByValue(configViews["DISP"]).Selected = true;
                                    editViewDdl.Items.FindByValue(configViews["EDIT"]).Selected = true;
                                }
                                else
                                {
                                    dispViewDdl.Items.FindByValue(defalutView).Selected = true;
                                    editViewDdl.Items.FindByValue(defalutView).Selected = true;
                                }

                                modifyPanel.Visible = true;

                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                errorLog(ex, true);
            }
        }

        private IEnumerable<string> getViews(SPFile file, ref string defautview)
        {
            if (defautview == null) throw new ArgumentNullException("defautview");

            byte[] xsnContent = file.OpenBinary();
            XmlDocument xsfDoc = new XmlDocument();
            XsnExtractor extractor = new XsnExtractor(xsnContent);
            byte[] xsfContent = extractor.Extract("manifest.xsf");
            using (MemoryStream xsfStream = new MemoryStream(xsfContent))
            {
                xsfDoc.Load(xsfStream);
            }

            // Validate Feature
            FeatureChecker checker = new FeatureChecker(xsfDoc);
            List<string> views = checker.ViewInfo;
            defautview = checker.DefaultView;
            return views;
        }

        #endregion

        #region Form Action

        private void ModifyExistingForm()
        {
            try
            {
                string xsnLocation = "";
                string relativeXSNLocation = "";
                _contentTypeName = ctDdl.SelectedItem.Text;
                if (!string.IsNullOrEmpty(_contentTypeName))
                {

                    Guid siteId = SPContext.Current.Site.ID;
                    Guid webId = SPContext.Current.Web.ID;
                    Guid listId = new Guid(Request["source"]);
                    string siteUrl = SPContext.Current.Site.Url;

                    SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (SPSite site = new SPSite(siteId))
                        {
                            using (SPWeb web = site.OpenWeb(webId))
                            {
                                web.AllowUnsafeUpdates = true;
                                SPList list = web.Lists[new Guid(tlLabel.Text)];
                                SPContentType cType = list.ContentTypes[_contentTypeName];

                                //update xsd
                                UpdateXSD(web, cType);
                                xsnLocation = web.Url + "/" + cType.ResourceFolder.Url + "/template.xsn";
                                //for alternative mapping
                                relativeXSNLocation = siteUrl + cType.ResourceFolder.ServerRelativeUrl + "/template.xsn";
                            }
                        }
                    });
                }
                //Response.Write("<script type='text/javascript'>window.frameElement.commitPopup('Operation Successful!')</script>");

                Response.Write("<script type='text/javascript'>var spOpener = new ActiveXObject('SharePoint.OpenXMLDocuments');if (spOpener != null) {var x = spOpener.CustomizeTemplate('" + relativeXSNLocation + "'); }window.frameElement.commitPopup('ok');</script>");
                //Response.Write("<script type='text/javascript'>var spOpener = new ActiveXObject('SharePoint.OpenXMLDocuments');if (spOpener != null) {var x = spOpener.CustomizeTemplate ('" + xsnLocation + "'); }</script>");

            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
            }
        }

        #region UpdateXSD
        private void UpdateXSD(SPWeb web, SPContentType cType)
        {
            //ExtractXSN
            ExtractXSD(Web, cType);
            //RegenerateXSD
            #region RegenerateXSD
            Guid siteId = SPContext.Current.Site.ID;
            Guid webId = SPContext.Current.Web.ID;
            Guid listId = new Guid(Request["source"]);
            SPList sourcelist = web.Lists[listId];
            SPWorkflowAssociation wf = null;

            wf = sourcelist.WorkflowAssociations[new Guid(wfDdl.SelectedValue)];
            if (wf == null)
            {
                foreach (SPContentType ct in sourcelist.ContentTypes)
                {
                    wf = ct.WorkflowAssociations[new Guid(wfDdl.SelectedValue)];
                    if (wf != null) break;
                }
            }
            if (wf != null)
            {
                SPList hisotryList = web.Lists[wf.HistoryListId];

                SPList list = web.Lists[new Guid(tlLabel.Text)];
                //SPContentType cType = list.ContentTypes[_contentTypeName];
                //Create Related Content ListInfo
                XListInfo rListInfo = new XListInfo();
                rListInfo.GenerateListInfo(sourcelist);
                rListInfo.AddListFieldReadOnly(sourcelist);
                //rListInfo.AddListField(sourcelist);

                //Create Main ListInfo
                XListInfo tListInfo = new XListInfo();
                tListInfo.GenerateListInfo(list);
                tListInfo.AddContentTypeInfo(cType);
                Dictionary<string, string> outcomes = GetTaskOutCome(wf, cType.Id);

                List<string> defaultFields = new List<string>();
                defaultFields.Add("Predecessors");
                defaultFields.Add("Priority");
                defaultFields.Add("Status");
                defaultFields.Add("PercentComplete");
                defaultFields.Add("AssignedTo");
                defaultFields.Add("Body");
                defaultFields.Add("StartDate");
                defaultFields.Add("DueDate");
                defaultFields.Add("WorkflowName");
                for (int i = 0; i < tListInfo.ContentTypeInfoList[0].FieldInfoList.Count; i++)
                {
                    XFieldInfo fieldInfo = tListInfo.ContentTypeInfoList[0].FieldInfoList[i];
                    if (defaultFields.Contains(fieldInfo.InternalName))
                    {
                        tListInfo.ContentTypeInfoList[0].FieldInfoList.Remove(fieldInfo);
                        i--;
                    }
                }

                //Create Workflow History ListInfo
                XListInfo whListInfo = new XListInfo();
                whListInfo.GenerateListInfo(hisotryList);
                whListInfo.AddContentTypeInfo(hisotryList.ContentTypes[0]);

                List<string> whViewFields = new List<string>();
                whViewFields.Add("Occurred");
                whViewFields.Add("Event");
                whViewFields.Add("User");
                whViewFields.Add("Description");
                whViewFields.Add("Outcome");
                List<XFieldInfo> whListViewFields = new List<XFieldInfo>();
                for (int i = 0; i < hisotryList.Fields.Count; i++)
                {
                    SPField hField = hisotryList.Fields[i];
                    if (whViewFields.Contains(hField.InternalName))
                    {
                        LabelFieldInfo fieldInfo = FieldInfoFactory.GetLabelFieldInfoDefinition(hField,
                            hisotryList.ContentTypes[0].Name);
                        if (fieldInfo != null)
                        {
                            whListViewFields.Add(fieldInfo);
                        }
                    }
                }

                WFXSNOperator xsnOperator = new WFXSNOperator
                {
                    SiteId = siteId,
                    WebId = webId,
                    ListId = list.ID,
                    CTypeId = cType.Id,
                    XSNTemplateFolder = Server.MapPath("/_layouts/ListForm2010/wf_xsn_template/"),
                    G_SiteUrl = web.Site.Url,
                    G_XSN_Url =
                        web.Site.Url + list.RootFolder.ServerRelativeUrl + "/" +
                        cType.ResourceFolder.Name + "/template.xsn",
                    RListInfo = rListInfo,
                    TListInfo = tListInfo,
                    OutComes = outcomes,
                    HListInfo = whListInfo,
                    HListViewFields = whListViewFields
                };

                string xsdTemp = @"C:\TempXsnFiles\" + cType.Id.ToString();
                xsnOperator.RefresehXSN(xsdTemp);
            }

            #endregion

            //PackageXSN&Upload
        }
        private Dictionary<string, string> ExtractXSD(SPWeb Web, SPContentType cType)
        {
            Dictionary<string, string> _targetXSDFiles = new Dictionary<string, string>();
            //Get ContentType
            string xsdURL = cType.ParentList.RootFolder.ServerRelativeUrl + "/" + cType.ResourceFolder.Name + "/template.xsn";
            string xsdTemp = @"C:\TempXsnFiles\" + cType.Id.ToString();
            SPFile m_file = Web.GetFile(xsdURL);
            if (m_file.Exists)
            {
                //Get XSN File Temp Location
                _targetXSDFiles.Add(xsdURL, xsdTemp);
                //Move XSD To Temp Location
                int size = 10 * 1024;
                using (Stream stream = m_file.OpenBinaryStream())
                {
                    Directory.CreateDirectory(xsdTemp);
                    string xsdTempLoaction = xsdTemp + "\\template.xsn";
                    using (FileStream fs = new FileStream(xsdTempLoaction, FileMode.Create, FileAccess.Write))
                    {
                        byte[] xsd_content = m_file.OpenBinary();
                        int nBytesRead = 0;
                        while ((nBytesRead = stream.Read(xsd_content, 0, xsd_content.Length)) > 0)
                        {
                            fs.Write(xsd_content, 0, nBytesRead);
                        }
                    }
                }
            }

            foreach (string xsdURL1 in _targetXSDFiles.Keys)
            {
                //Unpack XSN to local
                string xsdTemp1 = _targetXSDFiles[xsdURL];
                string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\template.xsn";
                string cmdString = string.Format("expand \"{0}\" \"{1}\" -f:*", xsdTempLoaction, xsdTemp);
                string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
            }

            return _targetXSDFiles;
            //Replace xsd file
            //Package and Upload
        }

        private string RunCommand(string cmdString, string xsdDictory)
        {
            Process p = new Process();
            //启动DOS程序
            p.StartInfo.WorkingDirectory = xsdDictory;
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;//不用Shell启动
            p.StartInfo.RedirectStandardInput = true;//重定向输入
            p.StartInfo.RedirectStandardOutput = true;//重定向输出
            p.StartInfo.CreateNoWindow = true;//不显示窗口
            p.Start();//开始进程
            p.StandardInput.WriteLine(cmdString);// 向cmd.exe输入command
            p.StandardInput.WriteLine("exit");//结束
            p.WaitForExit(60000);//等等执行完成
            string outPutString = p.StandardOutput.ReadToEnd();// 得到cmd.exe的输出
            p.Close();
            return outPutString;
        }
        #endregion

        private void CustomizeForm()
        {
            try
            {
                string xsnLocation = "";
                string relativeXSNLocation = "";
                string destFolderUrl;
                _contentTypeName = ctDdl.SelectedItem.Text;
                if (!string.IsNullOrEmpty(_contentTypeName))
                {

                    Guid siteId = SPContext.Current.Site.ID;
                    Guid webId = SPContext.Current.Web.ID;
                    Guid listId = new Guid(Request["source"]);
                    string siteUrl = SPContext.Current.Site.Url;

                    SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (SPSite site = new SPSite(siteId))
                        {
                            using (SPWeb web = site.OpenWeb(webId))
                            {
                                web.AllowUnsafeUpdates = true;
                                SPList sourcelist = web.Lists[listId];
                                SPWorkflowAssociation wf = null;

                                wf = sourcelist.WorkflowAssociations[new Guid(wfDdl.SelectedValue)];
                                if (wf == null)
                                {
                                    foreach (SPContentType ct in sourcelist.ContentTypes)
                                    {
                                        wf = ct.WorkflowAssociations[new Guid(wfDdl.SelectedValue)];
                                        if (wf != null) break;
                                    }
                                }
                                if (wf != null)
                                {
                                    SPList hisotryList = web.Lists[wf.HistoryListId];

                                    SPList list = web.Lists[new Guid(tlLabel.Text)];
                                    SPContentType cType = list.ContentTypes[_contentTypeName];
                                    xsnLocation = web.Url + "/" + cType.ResourceFolder.Url + "/template.xsn";
                                    //for alternative mapping
                                    relativeXSNLocation = siteUrl + cType.ResourceFolder.ServerRelativeUrl + "/template.xsn";

                                    if (!web.GetFile(xsnLocation).Exists)
                                    {
                                        //display_lb.aspx, edit_lb.aspx, new_lb.aspx
                                        destFolderUrl = cType.ResourceFolder.ServerRelativeUrl;
                                        string listParameter = "listId=" + list.ID.ToString();
                                        string cTypeParameter = "ctypeId=" + cType.Id.ToString();
                                        string uploadFileName = Microsoft.SharePoint.Utilities.SPUtility.GetGenericSetupPath(@"TEMPLATE\LAYOUTS\ListForm2010\TemplateWF.aspx");
                                        FileStream fileStream = File.Open(uploadFileName, FileMode.Open);
                                        web.Files.Add(destFolderUrl + "/display_lb.aspx", fileStream, true);
                                        cType.DisplayFormUrl = destFolderUrl + "/display_lb.aspx?" + listParameter + "%26" + cTypeParameter;
                                        web.Files.Add(destFolderUrl + "/edit_lb.aspx", fileStream, true);
                                        cType.EditFormUrl = destFolderUrl + "/edit_lb.aspx?" + listParameter + "%26" + cTypeParameter;

                                        //Pending, not sure about binding EventRecevier on WF list and related lists
                                        //RegisterEventReceiver(list);

                                        fileStream.Close();
                                        cType.Update();
                                        list.Update();

                                        #region Generate XSN
                                        //Create Related Content ListInfo
                                        XListInfo rListInfo = new XListInfo();
                                        rListInfo.GenerateListInfo(sourcelist);
                                        rListInfo.AddListFieldReadOnly(sourcelist);
                                        //rListInfo.AddListField(sourcelist);

                                        //Create Main Task ListInfo
                                        XListInfo tListInfo = new XListInfo();
                                        tListInfo.GenerateListInfo(list);
                                        tListInfo.AddContentTypeInfo(cType);
                                        Dictionary<string, string> outcomes = GetTaskOutCome(wf, cType.Id);

                                        List<string> defaultFields = new List<string>();
                                        defaultFields.Add("Predecessors");
                                        defaultFields.Add("Priority");
                                        defaultFields.Add("Status");
                                        defaultFields.Add("PercentComplete");
                                        defaultFields.Add("AssignedTo");
                                        defaultFields.Add("Body");
                                        defaultFields.Add("StartDate");
                                        defaultFields.Add("DueDate");
                                        defaultFields.Add("WorkflowName");
                                        for (int i = 0; i < tListInfo.ContentTypeInfoList[0].FieldInfoList.Count; i++)
                                        {
                                            XFieldInfo fieldInfo = tListInfo.ContentTypeInfoList[0].FieldInfoList[i];
                                            if (defaultFields.Contains(fieldInfo.InternalName))
                                            {
                                                if (!tListInfo.ContentTypeInfoList[0].ViewFieldList.Contains(fieldInfo))
                                                {
                                                    tListInfo.ContentTypeInfoList[0].ViewFieldList.Add(fieldInfo);
                                                }
                                            }
                                        }

                                        //Create Workflow History ListInfo
                                        XListInfo whListInfo = new XListInfo();
                                        whListInfo.GenerateListInfo(hisotryList);
                                        whListInfo.AddContentTypeInfo(hisotryList.ContentTypes[0]);

                                        List<string> whViewFields = new List<string>();
                                        whViewFields.Add("Occurred");
                                        whViewFields.Add("Event");
                                        whViewFields.Add("User");
                                        whViewFields.Add("Description");
                                        whViewFields.Add("Outcome");
                                        List<XFieldInfo> whListViewFields = new List<XFieldInfo>();
                                        for (int i = 0; i < hisotryList.Fields.Count; i++)
                                        {
                                            SPField hField = hisotryList.Fields[i];
                                            if (whViewFields.Contains(hField.InternalName))
                                            {
                                                LabelFieldInfo fieldInfo = FieldInfoFactory.GetLabelFieldInfoDefinition(hField, hisotryList.ContentTypes[0].Name);
                                                if (fieldInfo != null)
                                                {
                                                    whListViewFields.Add(fieldInfo);
                                                }
                                            }
                                        }

                                        WFXSNOperator xsnOperator = new WFXSNOperator
                                        {
                                            SiteId = siteId,
                                            WebId = webId,
                                            ListId = list.ID,
                                            CTypeId = cType.Id,
                                            XSNTemplateFolder = Server.MapPath("/_layouts/ListForm2010/wf_xsn_template/"),
                                            G_SiteUrl = site.Url,
                                            G_XSN_Url =
                                                site.Url + list.RootFolder.ServerRelativeUrl + "/" +
                                                cType.ResourceFolder.Name + "/template.xsn",
                                            RListInfo = rListInfo,
                                            TListInfo = tListInfo,
                                            OutComes = outcomes,
                                            HListInfo = whListInfo,
                                            HListViewFields = whListViewFields
                                        };

                                        xsnOperator.GenerateXSN();
                                        UploadFileToFormLib(xsnOperator);
                                        #endregion
                                    }
                                }
                            }
                        }
                    });
                }

                Response.Write("<script type='text/javascript'>var spOpener = new ActiveXObject('SharePoint.OpenXMLDocuments');if (spOpener != null) {var x = spOpener.CustomizeTemplate('" + relativeXSNLocation + "'); }window.frameElement.commitPopup('ok');</script>");

            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
            }
        }

        private void DefaultForm()
        {
            try
            {
                string xsnLocation;
                string destFolderUrl;
                _contentTypeName = ctDdl.SelectedItem.Text;
                if (!string.IsNullOrEmpty(_contentTypeName))
                {
                    Guid siteId = SPContext.Current.Site.ID;
                    Guid webId = SPContext.Current.Web.ID;
                    Guid listId = new Guid(Request["source"]);

                    SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (SPSite site = new SPSite(siteId))
                        {
                            using (SPWeb web = site.OpenWeb(webId))
                            {
                                web.AllowUnsafeUpdates = true;
                                SPList list = web.Lists[new Guid(tlLabel.Text)];
                                SPContentType cType = list.ContentTypes[_contentTypeName];


                                cType.DisplayFormUrl = list.DefaultDisplayFormUrl;
                                cType.EditFormUrl = list.DefaultEditFormUrl;

                                cType.Update();
                                UnBindingEventReceiver(list);
                                list.Update();

                                if (deleteCB.Checked)
                                {
                                    //display_lb.aspx, edit_lb.aspx, new_lb.aspx
                                    destFolderUrl = web.Url + "/" + cType.ResourceFolder.Url;
                                    xsnLocation = destFolderUrl + "/template.xsn";

                                    web.GetFile(destFolderUrl + "/edit_lb.aspx").Delete();
                                    //web.GetFile(destFolderUrl + "/new_lb.aspx").Delete();
                                    web.GetFile(destFolderUrl + "/display_lb.aspx").Delete();
                                    web.GetFile(xsnLocation).Delete();
                                    DeleteConfigItem(web, Convert.ToString(listId), Convert.ToString(cType.Id));
                                }
                                web.AllowUnsafeUpdates = false;
                            }
                        }
                    });
                }

                Response.Write("<script type='text/javascript'>window.frameElement.commitPopup('ok');</script>");


            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
            }
        }

        private static void DeleteConfigItem(SPWeb web, string mListID, string mContentTypeID)
        {
            if (string.IsNullOrEmpty(mListID) || string.IsNullOrEmpty(mContentTypeID)) return;
            try
            {
                SPList configList = web.Lists[Constants.LookupForm_Config_NAME];
                SPQuery query = new SPQuery
                {
                    Query =
                        "<Where><And><Eq><FieldRef Name='Title' /><Value Type='Text'>" + mListID +
                        "</Value></Eq><Eq><FieldRef Name='mContentType' /><Value Type='Text'>" + mContentTypeID +
                        "</Value></Eq></And></Where>"
                };
                SPListItemCollection items = configList.GetItems(query);
                ArrayList deletedList = new ArrayList();
                ArrayList unbindList = new ArrayList();
                foreach (SPListItem item in items)
                {
                    string sListId = Convert.ToString(item["sTitle"]);
                    unbindList.Add(sListId);
                    deletedList.Add(item.ID);
                }
                foreach (int itemId in deletedList)
                {
                    configList.Items.DeleteItemById(itemId);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        private static Dictionary<string, string> GetViewConfigItem(SPWeb web, string mListID, string mContentTypeID)
        {
            Dictionary<string, string> views = new Dictionary<string, string>();
            if (!string.IsNullOrEmpty(mListID) && !string.IsNullOrEmpty(mContentTypeID))
            {
                try
                {
                    SPList configList = web.Lists[Constants.LookupForm_Config_NAME];
                    SPQuery query = new SPQuery
                    {
                        Query =
                            "<Where><And><Eq><FieldRef Name='Title' /><Value Type='Text'>" + mListID +
                            "</Value></Eq><Eq><FieldRef Name='mContentType' /><Value Type='Text'>" + mContentTypeID +
                            "</Value></Eq></And></Where>"
                    };
                    SPListItemCollection items = configList.GetItems(query);
                    if (items.Count > 0)
                    {
                        string dispView = Convert.ToString(items[0]["mDispView"]);
                        string editView = Convert.ToString(items[0]["mEditView"]);

                        if (!string.IsNullOrEmpty(dispView))
                        {
                            views.Add("DISP", dispView);
                            views.Add("EDIT", editView);
                        }

                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            return views;
        }

        private void UpdateViewConfigItem()
        {
            try
            {
                _contentTypeName = ctDdl.SelectedItem.Text;
                if (!string.IsNullOrEmpty(_contentTypeName))
                {
                    Guid siteId = SPContext.Current.Site.ID;
                    Guid webId = SPContext.Current.Web.ID;
                    Guid listId = new Guid(Request["source"]);

                    SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (SPSite site = new SPSite(siteId))
                        {
                            using (SPWeb web = site.OpenWeb(webId))
                            {
                                web.AllowUnsafeUpdates = true;
                                SPList list = web.Lists[new Guid(tlLabel.Text)];
                                SPContentType cType = list.ContentTypes[_contentTypeName];

                                SPList configList = web.Lists[Constants.LookupForm_Config_NAME];
                                SPQuery query = new SPQuery
                                {
                                    Query =
                                        "<Where><And><Eq><FieldRef Name='Title' /><Value Type='Text'>" + listId +
                                        "</Value></Eq><Eq><FieldRef Name='mContentType' /><Value Type='Text'>" +
                                        cType.Id + "</Value></Eq></And></Where>"
                                };
                                SPListItemCollection items = configList.GetItems(query);
                                if (items.Count > 0)
                                {
                                    SPListItem item = items[0];
                                    item["mDispView"] = dispViewDdl.SelectedValue;
                                    item["mEditView"] = editViewDdl.SelectedValue;

                                    item.Update();
                                }
                                else
                                {
                                    SPListItem item = configList.Items.Add();
                                    item["Title"] = listId;
                                    item["mContentType"] = cType.Id;
                                    item["mDispView"] = dispViewDdl.SelectedValue;
                                    item["mEditView"] = editViewDdl.SelectedValue;

                                    item.Update();
                                }
                                web.AllowUnsafeUpdates = false;
                            }
                        }
                    });
                }

                Response.Write("<script type='text/javascript'>window.frameElement.commitPopup('ok');</script>");


            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
            }
        }

        public Dictionary<string, string> GetTaskOutCome(SPWorkflowAssociation assoc, SPContentTypeId taskContentTypeId)
        {
            Dictionary<string, string> outComes = new Dictionary<string, string>();

            #region GetXOML

            XmlDocument xomlDoc = new XmlDocument();
            xomlDoc.Load(new StringReader(assoc.SoapXml));

            string xsnPath = string.Empty;
            try
            {
                XmlNode node =
                    xomlDoc.SelectSingleNode("/WorkflowTemplate/Metadata/Instantiation_FormURI/string");

                xsnPath = node.InnerText;
                xsnPath = xsnPath.Replace(" ", "%20");
            }
            catch
            {
                xsnPath = assoc.InstantiationUrl;
            }
            string webRelativeFolder =
                xsnPath.Substring(0, xsnPath.LastIndexOf('/'));
            string xomlFileName =
                xsnPath.Substring(xsnPath.LastIndexOf('/') + 1);
            xomlFileName =
                xomlFileName.Replace(".xsn", ".xoml").Replace(".aspx", ".xoml");

            SPFolder wfFolder = assoc.ParentWeb.GetFolder(webRelativeFolder);
            SPFile xomlFile = wfFolder.Files[xomlFileName];

            xomlDoc = new XmlDocument();
            using (Stream xomlStream = xomlFile.OpenBinaryStream())
            {
                xomlDoc.Load(xomlStream);
            }
            XmlNamespaceManager xomlDocNamespaceManager = new XmlNamespaceManager(xomlDoc.NameTable);
            xomlDocNamespaceManager.AddNamespace("ns0",
                "clr-namespace:Microsoft.SharePoint.WorkflowActions;Assembly=Microsoft.SharePoint.WorkflowActions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=null");

            #endregion

            #region Find TaskNode

            string selectXPath = string.Format("//*[@ContentTypeId='{0}']", taskContentTypeId);
            XmlNode taskNode = xomlDoc.SelectSingleNode(selectXPath, xomlDocNamespaceManager);
            if (taskNode != null)
            {
                if (taskNode.Attributes["Outcomes"] != null)
                {
                    string[] outcomeStrs = taskNode.Attributes["Outcomes"].Value.Split(';');
                    foreach (string outcomeStr in outcomeStrs)
                    {
                        string[] outcomes = outcomeStr.Split(',');
                        outComes.Add(outcomes[0], outcomes[1]);
                    }
                }
                else
                {
                    outComes.Add("Finish", "Completed");
                }
                outComes.Add("Cancel", "");
            }

            #endregion

            return outComes;
        }

        #endregion

        #region GenerateXSN

        private static bool IsCustomizeFormExist(SPWeb web, SPContentType ct, ref SPFile xsnFile)
        {
            string destFolderUrl = web.Url + "/" + ct.ResourceFolder.Url;
            string xsnLocation = destFolderUrl + "/template.xsn";
            if (!web.GetFile(xsnLocation).Exists) return false;
            xsnFile = web.GetFile(xsnLocation);
            return true;
        }

        private void UploadFileToFormLib(WFXSNOperator p_XSNOperator)
        {
            try
            {
                System.Threading.Thread.Sleep(1000);
                // SPUtility.CreateFolderUnderList(mWeb,mList.Title,"defaultInfoPath");
                string xsnPath = p_XSNOperator.SaveFolder + "\\template\\template.xsn";
                SPSite site = new SPSite(p_XSNOperator.SiteId);
                SPWeb web = site.AllWebs[p_XSNOperator.WebId];
                SPList mlist = web.Lists[p_XSNOperator.ListId];
                SPContentType mCType = mlist.ContentTypes[p_XSNOperator.CTypeId];
                SPUtility.CreateFile(site, web, mlist, mCType.ResourceFolder.Name, "template.xsn", GetXsnFileStream(xsnPath));
            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
            }
        }

        private static byte[] GetXsnFileStream(string xsnPath)
        {
            byte[] buf = new byte[100];
            List<byte> bytes = new List<byte>();
            using (FileStream fs = File.Open(xsnPath, FileMode.Open, FileAccess.Read))
            {
                const int offset = 0;
                while ((fs.Read(buf, offset, buf.Length)) > 0)
                {
                    CopyOneStreamToStream(buf, bytes);
                    buf = new byte[100];
                }
            }

            return bytes.ToArray();
        }

        private static void CopyOneStreamToStream(IEnumerable<byte> byte1, ICollection<byte> byte2)
        {
            foreach (byte bt in byte1)
            {
                byte2.Add(bt);
            }
        }

        #endregion

        #region RegisterEventReceiver

        private static void RegisterEventReceiver(SPList list)
        {
            SPEventReceiverDefinition def1 = list.EventReceivers.Add();
            def1.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def1.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def1.Type = SPEventReceiverType.FieldAdded;
            def1.Name = "SPFieldChangeEventFieldAdded";
            def1.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def1.SequenceNumber = 1000;
            def1.Update();

            SPEventReceiverDefinition def2 = list.EventReceivers.Add();
            def2.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def2.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def2.Type = SPEventReceiverType.FieldUpdated;
            def2.Name = "SPFieldChangeEventFieldUpdated";
            def2.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def2.SequenceNumber = 1000;
            def2.Update();

            SPEventReceiverDefinition def3 = list.EventReceivers.Add();
            def3.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def3.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def3.Type = SPEventReceiverType.FieldDeleting;
            def3.Name = "SPFieldChangeEventFieldDeleting";
            def3.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def3.SequenceNumber = 1000;
            def3.Update();
        }

        private static void UnBindingEventReceiver(SPList list)
        {
            List<string> eventReceiverList = new List<string>
            {
                "LKPSPFieldChangeEventFieldAdded",
                "LKPSPFieldChangeEventFieldUpdated",
                "LKPSPFieldChangeEventFieldDeleting"
            };
            for (int i = 0; i < list.EventReceivers.Count; i++)
            {
                SPEventReceiverDefinition def = list.EventReceivers[i];
                if (!eventReceiverList.Contains(def.Name)) continue;
                def.Delete();
                i--;
            }
        }

        #endregion
    }
}
